import socket,_thread,sys
print('base_server module loaded.')
class http_parser:
    def __init__(self):
        self.status_code={
        100:'Continue',
        101:'Switching Protocol',
        200:'OK',
        201:'Created',
        202:'Accepted',
        203:'Non-Authoritative Information',
        204:'No Content',
        205:'Reset Content',
        206:'Partial Content',
        300:'Mutiple Choices',
        301:'Move Permanetly',
        302:'Found',
        303:'See Other',
        304:'Not Modified',
        305:'Use Proxy',
        306:'Unused',
        307:'Tenmporary Redirect',
        400:'Bad Request',
        401:'Unauthorized',
        402:'Payment Required',
        403:'Forbidden',
        404:'Not Found',
        405:'Method Not Allowed',
        406:'Not Acceptable',
        407:'Proxy Authentication Required',
        408:'Request Time-out',
        409:'Conflict',
        410:'Gone',
        411:'Length Required',
        412:'Precondition Failed',
        413:'Request Entity Too Large',
        414:'Request-URI Too Large',
        415:'Unsupported Media Type',
        416:'Requested range not satisfiable',
        417:'Expectation Failed',
        500:'Internal Server Error',
        501:'Not Implemented',
        502:'Bad Gateway',
        503:'Service Unavailable',
        504:'Gateway Time-out',
        505:'HTTP Version not supported'
        }
    def header_parser(self,header):
        pointer=0 #指针变量，指向两行CRLF的位置
        pointer=header.find(b'\r\n\r\n')+4
        head=header[:pointer-4]
        content=header[pointer:]
        head=head.decode('utf-8')
        head=head.splitlines()
        #print(head)
        parsed_header={
            'method':'',
            'path':'',
            'protocal':'',
            'detail':{}
        }
        FIRST_LINE=True
        for x in head:
            if FIRST_LINE:
                y=x.split(' ')
                parsed_header['method']=y[0]
                parsed_header['path']=y[1]
                parsed_header['protocal']=y[2]
                FIRST_LINE=False
            else:
                y=x.split(': ')
                parsed_header['detail'][y[0]]=y[1]
        return parsed_header,content
    def request_maker(self,status,protocal,extra):
        data='%s %s %s\r\n'%(protocal,status,self.status_code[status])
        for x in extra:
            data+='%s: %s\r\n'%(x,extra[x])
        return data
_parser=http_parser()
class http_error:
    def main(self,request_obj):
        request_obj.reply_body=b''
        request_obj.get_request()
        f=open('error.html','r')
        print(sys.exc_info()[2].tb_lineno)
        text=f.read()
        text=text.replace('[Value]',sys.exc_info()[1].__str__())
        text=text.encode('utf-8')
        request_obj.write_head(500,{'Content-Type':'text/html'})
        request_obj.write_content(text)
        request_obj.done()
_error=http_error()
class http_connection:
    class http_operation_obj:
        def __init__(self,client_obj,protocol):
            self.client_obj=client_obj
            self.client_obj.setblocking(False)
            self.client_obj.settimeout(0.1)
            self.protocol=protocol
            self.reply_body=b''
            self.thread_lock=_thread.allocate_lock()
        def get_request(self):
            req_raw=b''
            while True:
                try:
                    d=self.client_obj.recv(65536)
                    req_raw+=d
                    if d==b'':
                        return None
                except socket.timeout:
                    break
                except OSError:
                    if self.client_obj._closed:
                        return None
            return _parser.header_parser(req_raw)
        def write_head(self,code,info_list):
            self.reply_body+=('%s %s %s\r\n'%(self.protocol,code,_parser.status_code[code])).encode('utf-8')
            for x in info_list:
                self.reply_body+=('%s: %s\r\n'%(x,info_list[x])).encode('utf-8')
            self.reply_body+=b'\r\n'
        def write_content(self,content):
            self.reply_body+=content
        def done(self):
            self.client_obj.send(self.reply_body)
        def shut(self):
            self.client_obj.close()
        def send_raw(self,raw_data):
            self.client_obj.send(raw_data)
        def recv_raw(self,buffer_size):
            return self.client_obj.recv(buffer_size)
        def clear_buffer(self):
            self.reply_body=b''
        def acquire_lock(self):
            self.thread_lock.acquire()
        def release_lock(self):
            self.thread_lock.release()
    def connection(self,client,addr,func):
        request_obj=self.http_operation_obj(client,'HTTP/1.1')
        try:
            func(request_obj)
        except:
            _error.main(request_obj)
_connection=http_connection()
class base_http_server:
    def __init__(self,addr,port,main_function,thread_num):
        '''
        建立一个基于python3的WSGI服务器

        addr:地址

        port:端口

        main_function:服务器的执行函数

        thread_num:线程数

        '''
        self.socket_obj=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
        self.socket_obj.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
        self.socket_obj.setblocking(False)
        self.socket_obj.settimeout(1/1000)
        self.addr_port=(addr,port)
        self.main_func=main_function
        self.thread_num=thread_num
    class http_thread:
        def __init__(self,_self,socket_obj,thread_id):
            self.socket_obj=socket_obj
            self._self=_self
        def run(self):
            while True:
                try:
                    client,addr=self.socket_obj.accept()
                    _connection.connection(client,addr,self._self.main_func)
                except socket.timeout:
                    pass
                except ConnectionAbortedError:
                    pass
        def start(self):
            _thread.start_new_thread(self.run,())
    def serve_forever(self,backlog):
        '''
        立即启动服务器

        backlog:监听队列数量
        '''
        self.socket_obj.bind(self.addr_port)
        self.socket_obj.listen(backlog)
        thread_list=[]
        for x in range(1,self.thread_num):
            thread=self.http_thread(self,self.socket_obj,x)
            thread_list.append(thread)
        for x in thread_list:
            x.start()

        
    

    